

Matrix4 = function()
{
	/*******************************************/
	/*				Properties                 */
	/*******************************************/

		this.array = new Array();

		this.m00, this.m01, this.m02, this.m03;
		this.m10, this.m11, this.m12, this.m13;
		this.m20, this.m21, this.m22, this.m23;
		this.m30, this.m31, this.m32, this.m33;
		
	/*******************************************/
	/*				Constructor                */
	/*******************************************/	
	
		this.Identity();
		
}
  
/*********************************/
/*          Methods              */
/*********************************/

	
	Matrix4.prototype.MultMatrix = function(aMatrix )
	{
			var matrix = new Matrix4();

			matrix.array[0]=(this.array[0]*aMatrix.array[0])+(this.array[1]*aMatrix.array[4])+(this.array[2]*aMatrix.array[8])+(this.array[3]*aMatrix.array[12]);
			matrix.array[1]=(this.array[0]*aMatrix.array[1])+(this.array[1]*aMatrix.array[5])+(this.array[2]*aMatrix.array[9])+(this.array[3]*aMatrix.array[13]);
			matrix.array[2]=(this.array[0]*aMatrix.array[2])+(this.array[1]*aMatrix.array[6])+(this.array[2]*aMatrix.array[10])+(this.array[3]*aMatrix.array[14]);
			matrix.array[3]=(this.array[0]*aMatrix.array[3])+(this.array[1]*aMatrix.array[7])+(this.array[2]*aMatrix.array[11])+(this.array[3]*aMatrix.array[15]);

			matrix.array[4]=(this.array[4]*aMatrix.array[0])+(this.array[5]*aMatrix.array[4])+(this.array[6]*aMatrix.array[8])+(this.array[7]*aMatrix.array[12]);
			matrix.array[5]=(this.array[4]*aMatrix.array[1])+(this.array[5]*aMatrix.array[5])+(this.array[6]*aMatrix.array[9])+(this.array[7]*aMatrix.array[13]);
			matrix.array[6]=(this.array[4]*aMatrix.array[2])+(this.array[5]*aMatrix.array[6])+(this.array[6]*aMatrix.array[10])+(this.array[7]*aMatrix.array[14]);
			matrix.array[7]=(this.array[4]*aMatrix.array[3])+(this.array[5]*aMatrix.array[7])+(this.array[6]*aMatrix.array[11])+(this.array[7]*aMatrix.array[15]);

			matrix.array[8]=(this.array[8]*aMatrix.array[0])+(this.array[9]*aMatrix.array[4])+(this.array[10]*aMatrix.array[8])+(this.array[11]*aMatrix.array[12]);
			matrix.array[9]=(this.array[8]*aMatrix.array[1])+(this.array[9]*aMatrix.array[5])+(this.array[10]*aMatrix.array[9])+(this.array[11]*aMatrix.array[13]);
			matrix.array[10]=(this.array[8]*aMatrix.array[2])+(this.array[9]*aMatrix.array[6])+(this.array[10]*aMatrix.array[10])+(this.array[11]*aMatrix.array[14]);
			matrix.array[11]=(this.array[8]*aMatrix.array[3])+(this.array[9]*aMatrix.array[7])+(this.array[10]*aMatrix.array[11])+(this.array[11]*aMatrix.array[15]);

			matrix.array[12]=(this.array[12]*aMatrix.array[0])+(this.array[13]*aMatrix.array[4])+(this.array[14]*aMatrix.array[8])+(this.array[15]*aMatrix.array[12]);
			matrix.array[13]=(this.array[12]*aMatrix.array[1])+(this.array[13]*aMatrix.array[5])+(this.array[14]*aMatrix.array[9])+(this.array[15]*aMatrix.array[13]);
			matrix.array[14]=(this.array[12]*aMatrix.array[2])+(this.array[13]*aMatrix.array[6])+(this.array[14]*aMatrix.array[10])+(this.array[15]*aMatrix.array[14]);
			matrix.array[15]=(this.array[12]*aMatrix.array[3])+(this.array[13]*aMatrix.array[7])+(this.array[14]*aMatrix.array[11])+(this.array[15]*aMatrix.array[15]);

		this.multMatrix = matrix;
		return matrix;
	}
	
	Matrix4.prototype.MultVec4 = function(u )
	{
		var vec = new Vec4();

			vec.x=(this.array[0]*u.x)+(this.array[1]*u.y)+(this.array[2]*u.z)+(this.array[3]*u.w);
			vec.y=(this.array[4]*u.x)+(this.array[5]*u.y)+(this.array[6]*u.z)+(this.array[7]*u.w);
			vec.z=(this.array[8]*u.x)+(this.array[9]*u.y)+(this.array[10]*u.z)+(this.array[11]*u.w);
			vec.w=(this.array[12]*u.x)+(this.array[13]*u.y)+(this.array[14]*u.z)+(this.array[15]*u.w);
			
		return vec;
	}
       

	/*! brief Set the current matrix to Identity :
	 *
	 *          1   0   0   0
	 *          0   1   0   0
	 *          0   0   1   0
	 *          0   0   0   1
	 */
	Matrix4.prototype.Identity = function()
	{
	    this.array[0]=1; 	this.array[1]=0; 	this.array[2]=0; 	this.array[3]=0;
		this.array[4]=0; 	this.array[5]=1; 	this.array[6]=0; 	this.array[7]=0;
		this.array[8]=0; 	this.array[9]=0; 	this.array[10]=1; 	this.array[11]=0;
		this.array[12]=0;	this.array[13]=0; 	this.array[14]=0; 	this.array[15]=1;
	}
	
	Matrix4.Perspective = function( angle,  ratio,  near,  far)
	{
		this.mat= new Matrix4();

		var f= ((1.0) / (Math.tan(angle / 2.0)));

		this.mat.array[0]=f/ratio; 	this.mat.array[1]=0; 	this.mat.array[2]=0;                         	this.mat.array[3]=0;
		this.mat.array[4]=0; 		this.mat.array[5]=f; 	this.mat.array[6]=0;                         	this.mat.array[7]=0;
		this.mat.array[8]=0; 		this.mat.array[9]=0; 	this.mat.array[10]=((near+far)/(near-far)); 	this.mat.array[11]=((2*near*far)/(near-far));
		this.mat.array[12]=0;		this.mat.array[13]=0; 	this.mat.array[14]=-1;                       	this.mat.array[15]=1;

		return this.mat;
	}
	
	/*!	return the matrix formated for uniformMatrix4fv (by columns)	*/
	Matrix4.prototype.AsArray = function()
	{
		var varia = new Array();
		varia[0]=1;
		
		varia [0]		=this.array[0]; 				varia[1]	=this.array[4]; 				varia[2]	=this.array[8];							varia[3]	=	this.array[12];
		varia [4]		=this.array[1]; 				varia[5]	=this.array[5]; 				varia[6]	=this.array[9];                   		varia[7]	=	this.array[13];
		varia [8]		=this.array[2]; 				varia[9]	=this.array[6]; 				varia[10]	=this.array[10]; 						varia[11]	=	this.array[14];
		varia [12]	=this.array[3];					varia[13]	=this.array[7]; 				varia[14]	=this.array[11];                  		varia[15]	=	this.array[15];
		
		return varia ;
	}
	
	
	Matrix4.prototype.Translate= function( x,  y,  z)
	{
		this.array[3]=x;
		this.array[7]=y;
		this.array[11]=z;
	}
	
	/*!	brief Return the inverse translation	*/
	Matrix4.prototype.TranslateInverse	=	function(x,y,z)
	{
		this.array[3]=-x;
		this.array[7]=-y;
		this.array[11]=-z;
	}
	
	Matrix4.prototype.Print	=	function( )
	{
		return (" "+
				this.array[0] +" "+ this.array[1] +" "+ this.array[2] +" "+ this.array[3] +"\n"+ 
				this.array[4] +" "+ this.array[5] +" "+ this.array[6] +" "+ this.array[7] +"\n"+ 
				this.array[8] +" "+ this.array[9] +" "+ this.array[10] +" "+ this.array[11] +"\n"+ 
				this.array[12] +" "+ this.array[13] +" "+ this.array[14] +" "+ this.array[15] +"\n"
				)
	}
	
/******************************
 * 			Static
 ******************************/
	 
	Matrix4.Translation= function( v)
	{
		var mat = new Matrix4();
		
			mat.array [0]	= 1; 	mat.array[1]	=0; 	mat.array[2]	=0.0;	mat.array[3]	=	v.x;
			mat.array [4]	=0; 	mat.array[5]	=1; 	mat.array[6]	=0.0;   mat.array[7]	=	v.y;
			mat.array [8]	=0; 	mat.array[9]	=0; 	mat.array[10]	=1; 	mat.array[11]	=	v.z;
			mat.array [12]	=0;		mat.array[13]	=0; 	mat.array[14]	=0.0;	mat.array[15]	=	1;
			
		return mat;
	}

	Matrix4.TranslationInverse= function( v)
	{
		var mat = new Matrix4();
		
			mat.array [0]	= 1; 	mat.array[1]	=0; 	mat.array[2]	=0.0;	mat.array[3]	=	-v.x;
			mat.array [4]	=0; 	mat.array[5]	=1; 	mat.array[6]	=0.0;   mat.array[7]	=	-v.y;
			mat.array [8]	=0; 	mat.array[9]	=0; 	mat.array[10]	=1; 	mat.array[11]	=	-v.z;
			mat.array [12]	=0;		mat.array[13]	=0; 	mat.array[14]	=0.0;	mat.array[15]	=	1;
			
		return mat;
	}

	Matrix4.Scale= function( v)
	{
		var mat = new Matrix4();
		
			mat.array [0]	= v.x; 	mat.array[1]	=0; 	mat.array[2]	=0.0;	mat.array[3]	=	0;
			mat.array [4]	=0; 	mat.array[5]	=v.y; 	mat.array[6]	=0.0;   mat.array[7]	=	0;
			mat.array [8]	=0; 	mat.array[9]	=0; 	mat.array[10]	=v.z; 	mat.array[11]	=	0;
			mat.array [12]	=0;		mat.array[13]	=0; 	mat.array[14]	=0.0;	mat.array[15]	=	1;
			
		return mat;
	}

	Matrix4.ScaleInverse= function( v)
	{
		var mat = new Matrix4();
		
			mat.array [0]	= 1/v.x; 	mat.array[1]	=0; 		mat.array[2]	=0.0;		mat.array[3]	=	0;
			mat.array [4]	=0; 		mat.array[5]	=1/v.y; 	mat.array[6]	=0.0;   	mat.array[7]	=	0;
			mat.array [8]	=0; 		mat.array[9]	=0; 		mat.array[10]	=1/v.z; 	mat.array[11]	=	0;
			mat.array [12]	=0;			mat.array[13]	=0; 		mat.array[14]	=0.0;		mat.array[15]	=	1;
			
		return mat;
	}                
